/*基于GPLv2发布
2007/12/16
作者：旅行者2号
laf163@gmail.com*/

#include "CaptureThread.h"
#include "MainDialog.h"
#include "UpdateEvent.h"

extern MainDialog *pMainDlg;

QList <struct struct_arplist>arplist;

#ifndef WIN32
char *
strlwr (char *str)
{
  char *orig = str;
  for (; *str != '\0'; str++)
    *str = tolower (*str);
  return orig;
}
#endif

void
got_packet (u_char * args, const struct pcap_pkthdr *header,
	    const u_char * packet)
{
	if (packet == NULL)return;
	const struct struct_ethernet *ethernet;	//header
	const struct struct_arp *arp;	//arp packet
	ethernet = (struct struct_ethernet *) packet;
	arp = (struct struct_arp *) (packet + SIZE_ETHERNET);
	if ((arp->op != 0x100) && (arp->op != 0x200)){
		printf("arp->op!=0x100 and arp->op!=0x200.\n");
		return;
	}
	char op;//arp opcode
	char sha[18];//sender hardware address
	char tha[18];//target hardware address
	char sip[16];//sender IP address
	char tip[16];//target IP address
	op=arp->op == 0x100 ? 1 : 2;
	sprintf(sip,"%d.%d.%d.%d", arp->sip[0], arp->sip[1], arp->sip[2], arp->sip[3]);
	sprintf(tip,"%d.%d.%d.%d", arp->tip[0], arp->tip[1], arp->tip[2], arp->tip[3]);
	sprintf(sha,"%02x:%02x:%02x:%02x:%02x:%02x", arp->sha[0], arp->sha[1],
	  arp->sha[2], arp->sha[3], arp->sha[4], arp->sha[5]);
	sprintf(tha,"%02x:%02x:%02x:%02x:%02x:%02x", arp->tha[0], arp->tha[1],
	  arp->tha[2], arp->tha[3], arp->tha[4], arp->tha[5]);
	int i;
	struct struct_arplist tmparplist;
	bool isexist=false;
	for(i=0;i<arplist.count();i++){
		tmparplist=arplist.at(i);
		if(tmparplist.op!=op)continue;
		if(strcmp(tmparplist.sha,sha)!=0)continue;
		if(strcmp(tmparplist.tha,tha)!=0)continue;
		if(strcmp(tmparplist.sip,sip)!=0)continue;
		if(strcmp(tmparplist.tip,tip)!=0)continue;
		arplist[i].count++;
		isexist=true;
		break;
	}
	if(!isexist){
		tmparplist.op=op;
		strcpy(tmparplist.sha,sha);
		strcpy(tmparplist.tha,tha);
		strcpy(tmparplist.sip,sip);
		strcpy(tmparplist.tip,tip);
		tmparplist.count=1;
		arplist.append(tmparplist);
	}
	/*static QTime time;
	static bool flag=false;
	if(flag==false){
		time.start();
		flag=true;
	}
	if(time.elapsed()>5){//每5秒刷新一次
		emit pMainDlg->refresh();
		time.restart();
	}*/
	//emit pMainDlg->refresh();
	QUpdateEvent *event=new QUpdateEvent();
	QCoreApplication::postEvent(pMainDlg, event);
	return;
}

CaptureThread::CaptureThread()
{

}

CaptureThread::~CaptureThread()
{

}

void CaptureThread::run ()
{
    char errbuf[PCAP_ERRBUF_SIZE];
    char filter_str[100] = "";
    struct bpf_program fp;	/* hold compiled program */
    char *dev;
    pcap_t *descr;
    bpf_u_int32 maskp;		/* subnet mask */
    bpf_u_int32 netp;		/* ip */
    int pcap_time_out = 1000;
    int ret;

    //dev = pcap_lookupdev (errbuf);
    //if (dev == NULL){
	//	fprintf (stderr, "%s\n", errbuf);
	//	return;
	//}
	QSettings settings("ShadaLinux", "ShadaArp");
	dev=(char *)malloc(100);
	strcpy(dev,settings.value("net","null").toString().toStdString().c_str());
    ret = pcap_lookupnet (dev, &netp, &maskp, errbuf);
    if (ret == -1){
		fprintf (stderr, "%s\n", errbuf);
		return;
	}
    descr = pcap_open_live (dev, 65536, 1, pcap_time_out, errbuf);
    if (descr == NULL){
		printf ("pcap_open_live(): %s\n", errbuf);
		return;
	}
    sprintf (filter_str, "arp");
    if (pcap_compile (descr, &fp, filter_str, 1, netp) == -1){
		printf ("Error calling pcap_compile\n");
		return;
	}
    if (pcap_setfilter (descr, &fp) == -1){
		printf ("Error setting filter\n");
		return;
	}
	printf("在接口%s监听。 \n",dev);
	
    while (1){
		//printf ("wait for next packet:filter:%s\n", filter_str);
		if (pcap_dispatch (descr, -1, got_packet, NULL) == -1){
			printf ("error:%s\n", pcap_geterr (descr));
			printf("CaptureThread finished.\n");
			return;
		}
	}
}
